package com.nts.visionworks.business.endpoint.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.nts.visionworks.business.endpoint.domain.Building;
import com.nts.visionworks.business.endpoint.domain.BuildingFloor;
import com.nts.visionworks.business.endpoint.domain.BuildingFloorArea;
import com.nts.visionworks.business.endpoint.domain.BuildingFloorImage;
import com.nts.visionworks.business.endpoint.domain.EndPoint;
import com.nts.visionworks.business.endpoint.domain.EndPointCategory;
import com.nts.visionworks.business.endpoint.domain.EndPointScreenshot;
import com.nts.visionworks.business.endpoint.domain.ErrorRecord;
import com.nts.visionworks.business.endpoint.domain.IpType;
import com.nts.visionworks.business.endpoint.domain.PowerStatus;
import com.nts.visionworks.business.endpoint.service.EndPointService;
import com.nts.visionworks.core.hibernate.query.PaginationDirector;
import com.nts.visionworks.core.multipart.controller.MultipartController;
import com.nts.visionworks.core.multipart.domain.Archive;
import com.nts.visionworks.core.multipart.domain.Multipart;

/**
 * 끝점 관련 요청을 처리하기 위한 인터페이스를 제공한다.
 * @author Devcken
 */
@Controller
@RequestMapping("/endpoint")
public class EndPointController
{
	private final static Logger logger = LoggerFactory.getLogger(EndPointController.class);
	
	/**
	 * 끝점 관련 DAO를 주입받는다.
	 */
	@Resource(name="endPointService")
	private EndPointService _endPointService;
	
	/**
	 * 데이터 페이지네이션을 위한 지시자를 주입받는다.
	 */
	@Resource(name="paginationDirector")
	private PaginationDirector _paginationDirector;
	
	/**
	 * 끝점 목록 조회 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param searchCondition 끝점에 대한 검색 조건이 전달된다.
	 * @param areaId 끝점 위치 검색 조건이 전달된다.
	 * @return 조회된 끝점 목록을 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/list", method=RequestMethod.GET)
	public ModelAndView listEndPoints(HttpServletRequest request,
			EndPoint searchCondition,
			@RequestParam(value="areaId", required=false, defaultValue="0")Integer areaId)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			List<EndPoint> endPoints = this._endPointService.listEndPoints(searchCondition, areaId);
			
			map.put("endpoints", endPoints);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 추가 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param areaId 끝점의 층 구역 아이디가 전달된다.
	 * @param endPointName 끝점의 이름이 전달된다.
	 * @param ipType 끝점의 IP 주소 유형이 전달된다.
	 * @param ipAddress 끝점의 IP 주소가 전달된다.
	 * @return 추가된 끝점 정보를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/insert", method=RequestMethod.GET)
	public ModelAndView insertEndPoint(HttpServletRequest request,
			@RequestParam(value="areaId", required=true)Integer areaId,
			@RequestParam(value="endPointName", required=true)String endPointName,
			@RequestParam(value="ipType", required=true)Short ipType,
			@RequestParam(value="ipAddress", required=true)String ipAddress)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			EndPoint endPoint = this._endPointService.insertEndPoint(areaId, endPointName, IpType.convert(ipType), ipAddress);
			
			map.put("endPoint", endPoint);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 수정 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param endPoint 수정할 끝점 정보가 전달된다.
	 * @return 수정된 끝점 정보를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/update", method=RequestMethod.GET)
	public ModelAndView updateEndPoint(HttpServletRequest request,
			EndPoint endPoint)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			EndPoint updatedEndPoint = this._endPointService.updateEndPoint(endPoint);
			
			map.put("endPoint", updatedEndPoint);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 사용 불가 처리 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param endPointsId 사용 불가 처리할 끝점 아이디 목록이 전달된다.
	 * @return 사용 불가 처리된 끝점 개수를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/disable", method=RequestMethod.GET)
	public ModelAndView disableEndPoint(HttpServletRequest request,
			@RequestParam(value="endPointsId", required=true)List<Long> endPointsId)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			int affectedCount = this._endPointService.disableEndPoints(endPointsId);
			
			map.put("affectedCount", affectedCount);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * IP 주소 중복 검사 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param ipAddress 중복 검사할 IP 주소가 전달된다.
	 * @return IP 주소 중복 검사 결과를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/containsIpAddress", method=RequestMethod.GET)
	public ModelAndView containsIpAddress(HttpServletRequest request,
				@RequestParam(value="ipAddress", required=true)String ipAddress)
	{
		Map<String, Object> map = new HashMap<String, Object>();
			
		try
		{
			boolean isContains = this._endPointService.containsIpAddress(ipAddress);
			
			map.put("isContains", isContains);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 물리 주소 중복 검사 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param macAddress 중복 검사할 물리 주소가 전달된다.
	 * @return 물리 주소 중복 검사 결과를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/containsMacAddress", method=RequestMethod.GET)
	public ModelAndView containsMacAddress(HttpServletRequest request,
			@RequestParam(value="macAddress", required=true)String macAddress)
	{
		Map<String, Object> map = new HashMap<String, Object>();
			
		try
		{
			boolean isContains = this._endPointService.containsMacAddress(macAddress);
			
			map.put("isContains", isContains);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 카테고리 목록 조회 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @return 조회된 끝점 카테고리 목록을 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/category/list", method=RequestMethod.GET)
	public ModelAndView listEndPointCategories(HttpServletRequest request)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			List<EndPointCategory> categories = this._endPointService.listEndPointCategories();
			
			map.put("categories", categories);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 카테고리 저장 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param category 저장할 끝점 카테고리 정보가 전달된다.
	 * @return 저장된 끝점 카테고리 정보를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/category/save", method=RequestMethod.GET)
	public ModelAndView saveEndPointCategory(HttpServletRequest request,
			EndPointCategory category)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			this._endPointService.saveEndPointCategory(category);
			
			map.put("category", category);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 카테고리 삭제 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param categoryId 삭제할 끝점 카테고리 아이디가 전달된다.
	 * @return 끝점 카테고리 삭제 결과를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/category/delete", method=RequestMethod.GET)
	public ModelAndView deleteEndPointCategory(HttpServletRequest request,
			@RequestParam(value="categoryId", required=true)Long categoryId)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{	
			boolean result = false;
			
			this._endPointService.deleteEndPointCategory(categoryId);
			
			map.put("result", result);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 스크린샷 목록 조회 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param powerStatus 끝점에 대한 전원 상태 검색 조건이 전달된다.
	 * @param areaId 끝점의 층 구역 아이디 검색 조건이 전달된다.
	 * @param endPointId 스크린샷에 대한 끝점 아이디가 전달된다.
	 * @return 끝점 스크린샷 목록을 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/screenshot/list", method=RequestMethod.GET)
	public ModelAndView listEndPointScreenshots(HttpServletRequest request,
			@RequestParam(value="powerStatus", required=false, defaultValue="0")Short powerStatus,
			@RequestParam(value="areaId", required=false, defaultValue="0")Integer areaId,
			@RequestParam(value="endPointId", required=false, defaultValue="0")Long endPointId)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			List<EndPointScreenshot> screenshots = this._endPointService.listEndPointScreenshots(PowerStatus.convert(powerStatus), areaId, endPointId);
			
			map.put("screenshots", screenshots);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 스크린샷 저장 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param multipart 멀티파트 리졸버에 의해 전달된 멀티파트 영속성 인스턴스로 멀티파트 정보를 담고 있다.
	 * @param bindingResult HTTP 요청에 대한 바인딩 결과를 나타낸다. 
	 * @param request HTTP 요청으로 멀티파트 요청으로 변환되기 전 상태를 나타낸다.
	 * @param response HTTP 응답으로 멀티파트 요청에 대한 응답을 나타낸다.
	 * @param session 멀티파트 요청에 상응하는 HTTP 세션을 나타낸다.
	 * @param endPointId 스크린샷을 저장할 끝점의 아이디가 전달된다.
	 * @return 스크린샷 저장 결과를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/screenshot/save", method=RequestMethod.GET)
	public ModelAndView saveEndPointScreenshot(Multipart multipart,
			BindingResult bindingResult,
			HttpServletRequest request,
			HttpServletResponse response,
			HttpSession session,
			@RequestParam(value="endPointId", required=true)Long endPointId)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			MultipartController multipartController = new MultipartController();
			
			ModelAndView modelAndView = multipartController.upload(multipart, bindingResult, request, response, session);
			
			Map<String, Object> multipartMap = modelAndView.getModel();
			
			if (multipartMap.containsKey("result") && multipartMap.get("result").equals(true))
			{
				Archive[] archives = (Archive[])multipartMap.get("archives");
				
				if (archives.length != 1)
				{
					map.put("result", false);
				}
				else
				{
					Archive archive = archives[0];
					
					boolean result = this._endPointService.saveEndPointScreenshot(endPointId, archive.getArchiveId());
					
					map.put("result", result);
				}
			}
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 빌딩 목록 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @return 조회된 빌딩 목록을 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/building/list", method=RequestMethod.GET)
	public ModelAndView listBuildings(HttpServletRequest request)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			List<Building> buildings = this._endPointService.listBuildings();
			
			map.put("buildings", buildings);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 빌딩 정보 저장 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param building 저장할 빌딩 정보가 전달된다.
	 * @return 저장된 빌딩 정보를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/building/save", method=RequestMethod.GET)
	public ModelAndView saveBuilding(HttpServletRequest request,
			Building building)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			this._endPointService.saveBuilding(building);
			
			map.put("building", building);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 빌딩 층 정보 저장 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param floor 저장할 빌딩 층 정보가 전달된다.
	 * @return 저장된 빌딩 층 정보를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/floor/save", method=RequestMethod.GET)
	public ModelAndView saveBuilding(HttpServletRequest request,
			BuildingFloor floor,
			@RequestParam(value="buildingId", required=true)Integer buildingId)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			this._endPointService.saveBuildingFloor(floor, buildingId);
			
			map.put("floor", floor);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 빌딩 층 구역 정보 저장 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param floor 저장할 빌딩 층 구역 정보가 전달된다.
	 * @return 저장된 빌딩 층 구역 정보를 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/area/save", method=RequestMethod.GET)
	public ModelAndView saveBuilding(HttpServletRequest request,
			BuildingFloorArea area,
			@RequestParam(value="floorId", required=true)Integer floorId)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			this._endPointService.saveBuildingFloorArea(area, floorId);
			
			map.put("area", area);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 빌딩 층 이미지 목록 조회 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param floorId 층 이미지를 조회할 빌딩 층 아이디가 전달된다.
	 * @return 빌딩 층 이미지 목록을 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/floor/images", method=RequestMethod.GET)
	public ModelAndView listBuildingFloorImages(HttpServletRequest request,
			@RequestParam(value="floorId", required=true)Integer floorId)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			List<BuildingFloorImage> floorImages = this._endPointService.listBuildingFloorImages(floorId);
			
			map.put("floorImages", floorImages);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 오류 기록 조회 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param endPointId 조회하려는 오류 기록에 대한 끝점 아이디가 전달된다.
	 * @return 조회된 오류 기록 목록을 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/error/list", method=RequestMethod.GET)
	public ModelAndView listEndPointErrorRecords(HttpServletRequest request,
			@RequestParam(value="endPointId", required=true)Long endPointId)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			List<ErrorRecord> errorRecords = this._endPointService.listErrorRecords(endPointId);
			
			map.put("errorRecords", errorRecords);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
	
	/**
	 * 끝점 오류 기록 저장 요청에 대한 처리 결과를 뷰로 전달한다.
	 * @param request HTTP 서블릿에 대한 요청 정보가 전달된다.
	 * @param endPointId 저장하려는 오류 기록에 대한 끝점 아이디가 전달된다.
	 * @param errorRecord 저장하려는 오류 기록이 전달된다.
	 * @return 저장된 오류 기록을 포함하는 {@link org.springframework.web.servlet.ModelAndView.ModelAndView} 개체를 반환한다.
	 */
	@RequestMapping(value="/error/save", method=RequestMethod.GET)
	public ModelAndView saveEndPointErrorRecords(HttpServletRequest request,
			@RequestParam(value="endPointId", required=true)Long endPointId,
			ErrorRecord errorRecord)
	{
		Map<String, Object> map = new HashMap<String, Object>();
		
		try
		{
			this._endPointService.saveErrorRecord(endPointId, errorRecord);
			
			map.put("errorRecord", errorRecord);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return new ModelAndView("jsonView", map);
	}
}